home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Libraries / GrafSys 2.0 / Demos / Full Demo / GrafSys 2.0 Full Demo.p next >
Encoding:
Text File  |  1993-12-17  |  9.2 KB  |  333 lines  |  [TEXT/PJMM]

  1. program SolidModel;
  2.  
  3.     uses
  4.         Matrix, Transformations, OffscreenCore, GrafSysCore, GrafSysScreen, GrafSysObject, Resources, OffScreenGraphics, GrafSysC;
  5.  
  6. {This program demonstrates a sample implementation of the painter's algorithm     }
  7. {with back-face removal and full triangle filling                                         }
  8.  
  9.     const
  10.         cMaxPoly = 100;
  11.         maxDepth = 2000;
  12.         minDepth = 0;
  13.         cTheWindow = 400;
  14.         degrees = 0.01745329; (* π/180 *)
  15.  
  16.     type
  17.  
  18.         trigon = record
  19.                 p: array[1..3] of integer;
  20.                 deepz: real;
  21.                 shallowz: real;
  22.                 color: integer;
  23.             end;
  24.  
  25.         screenTrigon = record
  26.                 p: array[1..3] of point;
  27.                 deepz: real;
  28.                 shallowz: real;
  29.                 color: integer;
  30.             end;
  31.  
  32.         Tsurfaces = array[1..cMaxPoly] of trigon;
  33.  
  34.         TSolid3D = object(TSGenericObject3D)
  35.                 numSurfaces: integer;
  36.                 surfaces: Tsurfaces;
  37.                 procedure init;
  38.                 override;
  39.                 procedure addPoly (p1, p2, p3: integer; color: integer);
  40.                 procedure draw;
  41.                 override;
  42.             end;
  43.  
  44.     var
  45.         screenBuf: array[1..cMaxPoly] of screenTrigon;
  46.         screenBufNum: integer;
  47.  
  48.     procedure TSolid3D.init;
  49.         override;
  50.     begin
  51.         inherited init;
  52.         numsurfaces := 0;
  53.     end;
  54.  
  55.     procedure TSolid3D.addPoly (p1, p2, p3: integer; color: integer);
  56.  
  57.         var
  58.             thePoly: trigon;
  59.  
  60.     begin
  61.         if numSurfaces < cMaxPoly then
  62.             begin
  63.                 numSurfaces := numSurfaces + 1;
  64.                 thePoly.p[1] := p1;
  65.                 thePoly.p[2] := p2;
  66.                 thePoly.p[3] := p3;
  67.                 thePoly.deepZ := -1;
  68.                 thePoly.color := color;
  69.                 surfaces[numSurfaces] := thePoly;
  70.             end;
  71.     end;
  72.  
  73.     procedure TSolid3D.draw;
  74.         override;
  75.  
  76.         var
  77.             i, k: integer;
  78.             h, v: integer;
  79.             thePoint: Vector4;
  80.             x, y, z: Real;
  81.             zbyd: Real;
  82.             index: integer;
  83.             buffer, offset: integer;
  84.             tempTrigon: screenTrigon;
  85.             l, m: integer;
  86.             thePlane: array[1..3] of Vector4;
  87.  
  88.     begin
  89.         Transform2(FALSE); (* transform and gather bounds data *)
  90.         InsetRect(oldBounds, -2, -2);
  91.         EraseRect(oldBounds);
  92.     (* now build the buffer for sorting triangles *)
  93.         screenBufNum := 0; (* no triangles to draw *)
  94.         for i := 1 to numSurfaces do
  95.             begin
  96.                 tempTrigon.deepz := -1;
  97.                 tempTrigon.color := surfaces[i].color;
  98.                 for k := 1 to 3 do
  99.                     begin
  100.         {get points and store them in triangle struct }
  101.                         index := surfaces[i].p[k];
  102.                         self.GenIndex(index - 1, buffer, offset);
  103.                         thePoint := theBufs[buffer]^[offset].transformed;
  104. {apply eye trafo as in ToScreen }
  105. {if current3DPort^.useEye then}
  106. {thePoint := VMult(thePoint, current3DPort^.MasterTransform); (* transform point so we can project *)
  107. {GetVector4(thePoint, x, y, z); (* return to real *)
  108.  
  109.                         thePlane[k] := thePoint;
  110.                         h := theBufs[buffer]^[offset].screenx;
  111.                         v := theBufs[buffer]^[offset].screeny;
  112.                         z := thePoint[3]; (* danger! direct access to data structure *)
  113.  
  114. {if current3DPort^.projection = parallel then {}
  115. {begin {}
  116. {h := Trunc(x) + current3DPort^.center.h; {}
  117. {v := -Trunc(y) + current3DPort^.center.v {}
  118. {end {}
  119. {else {}
  120. {begin {}
  121. {zbyd := 1 / (z / current3DPort^.d + 1);{}
  122. {h := Trunc(x * zbyd) + current3DPort^.center.h; (* do perspective transformation *)
  123. {v := -Trunc(y * zbyd) + current3DPort^.center.v;{}
  124. {end;{}
  125.  
  126.             {save screen positions }
  127.                         tempTrigon.p[k].h := h;
  128.                         tempTrigon.p[k].v := v;
  129.             {check for new deepz}
  130.                         if z > tempTrigon.deepz then
  131.                             tempTrigon.deepz := z;
  132.  
  133.                     end; (* for k  *)
  134.  
  135.         {now insert the tempTrigon at the correct place in the screen trigon. Simple insertion sort }
  136.                 if (tempTrigon.deepz > 0) and IsVisible(thePlane[1], thePlane[2], thePlane[3]) then
  137.                     begin (* we must insert. otherwise z<0 : don't draw *)
  138.                         k := 1;
  139.                         while (k <= screenBufNum) and (tempTrigon.deepZ < screenBuf[k].deepz) do
  140.                             k := k + 1;
  141.  
  142.             (* now k points to the place we have to insert it or to the end of the buffer *)
  143.                         if k <= screenBufNum then
  144.                             begin (* we must move all polys up one to make space *)
  145.                                 for l := screenBufNum downto k do
  146.                                     screenBuf[l + 1] := screenBuf[l];
  147.                             end;
  148.                         screenBuf[k] := tempTrigon;
  149.                         screenBufNum := screenBufNum + 1;
  150.                     end;
  151.             end; (* for i *)
  152.  
  153. { now all triangles are sorted by ascending z values. draw them }
  154.         i := 1;
  155.         while i <= screenBufNum do
  156.             begin
  157.                 tempTrigon := screenBuf[i];
  158.                 FillTriangle(tempTrigon.p[1], tempTrigon.p[2], tempTrigon.p[3], tempTrigon.Color, FALSE); {tempTrigon.Color}
  159.                 i := i + 1;
  160.             end;
  161.     end;
  162.  
  163.     procedure BuildObject (var Obj: TSolid3D);
  164.  
  165.         var
  166.             OK: longint;
  167.             theGreen: RGBColor;
  168.             dummyBool: boolean;
  169.  
  170.     begin
  171.  
  172.         OK := Obj.AddPoint(100, 100.0, -100); (* 1 *)
  173.         OK := Obj.AddPoint(-100, 100.0, -100);
  174.         OK := Obj.AddPoint(-100, -100.0, -100);
  175.         OK := Obj.AddPoint(100, -100.0, -100);
  176.  
  177.         OK := Obj.AddPoint(100, 100.0, 100); (* 5 *)
  178.         OK := Obj.AddPoint(-100, 100.0, 100);
  179.         OK := Obj.AddPoint(-100, -100.0, 100);
  180.         OK := Obj.AddPoint(100, -100.0, 100);
  181.  
  182.         Obj.addPoly(1, 2, 3, 16); (* top *)
  183.         Obj.addPoly(3, 4, 1, 16);
  184.  
  185.         obj.addPoly(7, 6, 5, 32); (* bottom *)
  186.         obj.addPoly(5, 8, 7, 32);
  187.  
  188.         obj.addPoly(1, 5, 6, 48); (* left *)
  189.         obj.addPoly(6, 2, 1, 48);
  190.  
  191.         obj.addpoly(8, 4, 3, 128); (* right *)
  192.         obj.addPoly(3, 7, 8, 128);
  193.  
  194.         obj.addpoly(1, 4, 8, 144); (* front *)
  195.         obj.addpoly(8, 5, 1, 144);
  196.  
  197.         obj.addPoly(7, 3, 2, 200); (* back *)
  198.         obj.addPoly(2, 6, 7, 200);
  199.     end;
  200.  
  201.     procedure Check (theErr: integer);
  202.     begin
  203.         if theErr <> noErr then
  204.             DebugStr(InterPretError(theErr));
  205.     end;
  206.  
  207. {MAIN PROGRAM}
  208.  
  209.     var
  210.         theCube: TSolid3D;
  211.         theCoords: TSObject3D;
  212.         theFighter: TSObject3D;
  213.         theShuttle: TSObject3D;
  214.         EyeLoc: Vector4;
  215.         theWindow: WindowPtr;
  216.         dummyLong: longint;
  217.         copyRect: Rect;
  218.         time: longint;
  219.         done: boolean;
  220.         direction: integer;
  221.         depth: integer;
  222.  
  223. begin
  224.     done := FALSE;
  225.     direction := 10;
  226.     depth := 0;
  227.     InitCursor;
  228.     InitGrafSys;
  229.     theWindow := GetNew3DWindow(cTheWindow, pointer(-1));
  230.     SetVector4(EyeLoc, 0, 0, -300);
  231.     SetEyeChar(TRUE, EyeLoc, 0, 0, 0, 90 * degrees, fast);
  232.     New(theCube);
  233.     theCube.Init;
  234.     BuildObject(theCube);
  235.     theCube.Translate(0, 0, 0);
  236. {    theCube.Draw;}
  237.  
  238. (* now load the coord sys to animate left to the cube *)
  239.     theCoords := GetNewNamedObject('XYZ Coord');
  240.     theCoords.Translate(-300, 300, 0);
  241.     theCoords.SetAutoerase(TRUE);
  242.  
  243. (* now load the fighter to animate right of the cube *)
  244.     theFighter := GetNewNamedObject('theFighter');
  245.     theFighter.Translate(300, 300, 0);
  246.     theFighter.SetAutoerase(TRUE);
  247.  
  248. (* now load the space shuttle *)
  249.     theShuttle := GetNewNamedObject('Shuttle');
  250.     theShuttle.Scale(2, 2, 2);{}
  251.     theShuttle.Translate(0, -130, 0);
  252.     theShuttle.SetAutoerase(TRUE);
  253.  
  254. (* Now Add legend to window *)
  255.     MoveTo(theWindow^.portRect.left + 10, theWindow^.portRect.bottom - 20);
  256.     TextFont(Courier);
  257.     TextSize(10);
  258.     DrawString('Press Mousebutton to halt,');
  259.     MoveTo(theWindow^.portRect.left + 10, theWindow^.portRect.bottom - 10);
  260.     DrawString('doubleclick to exit');
  261.  
  262.     MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 180);
  263.     DrawString('  Animation Stats:');
  264.     MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 170);
  265.     DrawString('  ----------------');
  266.     MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 160);
  267.     DrawString('  Number of Objects :  4');
  268.     MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 150);
  269.     DrawString('  Number of Points  : 97');
  270.     MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 140);
  271.     DrawString('  Number of Lines   : 87');
  272.     MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 130);
  273.     DrawString('  Number of Surfaces: 12');
  274.     MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 100);
  275.     DrawString('  Animation: Full Off-Screen');
  276.     MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 90);
  277.     DrawString('             Buffering');
  278.     SetRect(copyRect, theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 190, theWindow^.portRect.right - 5, theWindow^.portRect.bottom - 80);
  279.     FrameRect(copyRect);
  280.     theCube.Draw;
  281.     theCoords.Draw;
  282.     theFighter.Draw;
  283.     theShuttle.Draw;
  284.     Check(AttachOffscreen(theWindow, pointer(-1))); (* does automatic sanity check *)
  285.     repeat
  286.         Check(BeginOSDraw(theWindow));
  287.         theCube.Draw; (* erase it and redraw it*)
  288.         theCoords.Draw;
  289.         theFighter.Draw;
  290.         theShuttle.Draw;
  291.         Check(EndOSDraw(theWindow));
  292.  
  293.         UnionRect(theCube.oldBounds, theCube.bounds, copyrect);
  294.         Check(CopyOS2Screen(theWindow, copyrect, srcCopy));
  295.         UnionRect(theCoords.oldBounds, theCoords.bounds, copyrect);
  296.         Check(CopyOS2Screen(theWindow, copyrect, srcCopy));
  297.         UnionRect(theFighter.oldBounds, theFighter.bounds, copyrect);
  298.         Check(CopyOS2Screen(theWindow, copyrect, srcCopy));
  299.         UnionRect(theShuttle.oldBounds, theShuttle.bounds, copyrect);
  300.         Check(CopyOS2Screen(theWindow, copyrect, srcCopy));
  301.  
  302. {Delay(1, dummyLong);{}
  303.  
  304.         theCube.Rotate(5 * degrees, 2 * degrees, 1 * degrees);
  305.         theCube.Translate(0, 0, 3 * direction);
  306.         theCoords.Rotate(2 * degrees, 5 * degrees, 1 * degrees);
  307. {theCoords.Translate(0, 0, 0 * direction);{}
  308.         theFighter.Rotate(2 * degrees, 1 * degrees, 5 * degrees);
  309. {theFighter.Translate(0, 0, direction);{}
  310.         theShuttle.Rotate(7 * degrees, 0 * degrees, 7 * degrees);
  311. {theShuttle.Translate(0, 0, direction);{}
  312.  
  313.         depth := depth + direction;
  314.         if depth > maxdepth then
  315.             direction := -direction;
  316.         if depth <= minDepth then
  317.             direction := -direction;
  318.  
  319.         if button then
  320.             begin
  321.                 time := TickCount - time;
  322.                 if time < GetDblTime div 2 then
  323.                     done := true
  324.                 else
  325.                     repeat
  326.                     until not button;
  327.                 time := tickCount;
  328.             end;
  329.  
  330.     until done;
  331.     repeat
  332.     until not button;
  333. end.